import 'package:inmotion_protocol/lorin/bean/common/date.dart';
import 'package:inmotion_protocol/lorin/lorin_message.dart';
import 'dart:typed_data';
import 'package:inmotion_protocol/lorin/constant.dart';
import 'package:inmotion_protocol/lorin/codec.dart';
import 'package:inmotion_protocol/lorin/protocol.dart';
import 'package:inmotion_protocol/lorin/util.dart';
import 'package:inmotion_protocol/util/aes.dart';
import 'package:inmotion_protocol/util/byte_util.dart';

class LorinGeneralMessageFactory {
  static LorinMessage genMsg(int format, int key, Uint8ClampedList? tab,
      int length, Uint8ClampedList data, Uint8ClampedList? check) {
    LorinMessageData? msgData;
    if (Util.isSpecialMany2ManyData(format)) {
      msgData = LorinSpecialMessageData.sFrom(
          Constant.dataTypeSpecialMany2Many, data, 0);
    } else if (Util.isSpecialOne2ManyData(format)) {
      msgData = LorinSpecialMessageData.sFrom(
          Constant.dataTypeSpecialOne2Many, data, 0);
    } else if (Util.isSpecialOne2OneData(format)) {
      msgData = LorinSpecialMessageData.sFrom(
          Constant.dataTypeSpecialOne2One, data, 0);
    } else if (Util.isGeneralMany2ManyData(format)) {
      msgData = LorinGeneralMessageData.sFrom(
          Constant.dataTypeGeneralMany2Many, data, 0);
    } else if (Util.isGeneralOne2ManyData(format)) {
      msgData = LorinGeneralMessageData.sFrom(
          Constant.dataTypeGeneralOne2Many, data, 0);
    } else if (Util.isGeneralOne2OneData(format)) {
      msgData = LorinGeneralMessageData.sFrom(
          Constant.dataTypeGeneralOne2One, data, 0);
    } else {
      msgData = LorinUnknownMessageData();
    }
    msgData ??= LorinUnknownMessageData();
    return LorinMessage(LorinMessage.HEAD, ByteUtil.toUint8(format),
        ByteUtil.toUint8(key), tab, ByteUtil.toUint8(length), msgData, check);
  }

  /*
  static LorinMessage genGeneralOne2OneMsg(int channel, int property,
      [Uint8ClampedList? para,
      Uint8ClampedList? tab,
      int checkType = Constant.checkTypeParity,
      bool encrypt = false]) {
    LorinGeneralMessageData msgData = LorinGeneralMessageData(null, null,
        ByteUtil.toUint8(channel), ByteUtil.toUint8(property), para);

    int format = Util.calFormat(
        tab == null ? Constant.noTab : Constant.hasTab,
        checkType,
        encrypt ? Constant.hasEncrypt : Constant.noEncrypt,
        Constant.dataTypeGeneralOne2One);
    int length = msgData.dataLength();
    return LorinMessage(LorinMessage.HEAD, ByteUtil.toUint8(format), null, tab,
        ByteUtil.toUint8(length), msgData, null);
  }

  static LorinMessage genGeneralOne2ManyMsg(
      int target, int channel, int property,
      [Uint8ClampedList? para,
      Uint8ClampedList? tab,
      int checkType = Constant.checkTypeParity,
      bool encrypt = false]) {
    LorinGeneralMessageData msgData = LorinGeneralMessageData(
        null,
        ByteUtil.toUint8(target),
        ByteUtil.toUint8(channel),
        ByteUtil.toUint8(property),
        para);
    int format = Util.calFormat(
        tab == null ? Constant.noTab : Constant.hasTab,
        checkType,
        encrypt ? Constant.hasEncrypt : Constant.noEncrypt,
        Constant.dataTypeGeneralOne2Many);
    int length = msgData.dataLength();
    return LorinMessage(LorinMessage.HEAD, ByteUtil.toUint8(format), null, tab,
        ByteUtil.toUint8(length), msgData, null);
  }
  */

  static LorinMessage genGeneralMsg(
    int channel,
    int property, [
    Uint8ClampedList? para,
    int? source,
    int? target,
    int? tab,
  ]) {
    return genGeneralMany2ManyMsg(source, target, channel, property, para,
        tab == null ? null : Util.genTab(tab));
  }

  static LorinMessage genGeneralMany2ManyMsg(
    int? source,
    int? target,
    int channel,
    int property, [
    Uint8ClampedList? para,
    Uint8ClampedList? tab,
    int checkType = Constant.checkTypeParity,
    bool encrypt = false,
  ]) {
    var newSource = source ??=
        ProtocolGlobal.isBleSend ? Constant.sourceApp : Constant.sourceCloudBox;
    var newTarget = target ??= Constant.deviceUnknown;
    print(
        'genGeneralMany2ManyMsg: source = $source, target = $target, channel = $channel, property = $property, para = $para, tab = $tab');
    LorinGeneralMessageData msgData = LorinGeneralMessageData(
        ByteUtil.toUint8(newSource),
        ByteUtil.toUint8(newTarget),
        ByteUtil.toUint8(channel),
        ByteUtil.toUint8(property),
        para);
    int format = Util.calFormat(
        tab == null ? Constant.noTab : Constant.hasTab,
        checkType,
        encrypt ? Constant.hasEncrypt : Constant.noEncrypt,
        Constant.dataTypeGeneralMany2Many);
    int length = msgData.dataLength();
    return LorinMessage(LorinMessage.HEAD, ByteUtil.toUint8(format), null, tab,
        ByteUtil.toUint8(length), msgData, null);
  }

  /* **************************** 通道0-连接 START ************************** */

  /// 生成请求从机加密key消息
  static LorinMessage genRequestEncryptedKeyMsg() {
    return genGeneralMany2ManyMsg(null, null, Constant.channelVerify,
        Constant.PROPERTY_VERIFY_IN_CHANNEL_VERIFY);
  }

  /**
   *
   *
   * @param originKey 从机应答的随机密码，明文
   * @return msg
   */

  /// 生成验证密码消息
  static LorinMessage genVerifyCryptKeyMsg(Uint8ClampedList originKey) {
    return genGeneralMany2ManyMsg(
        null,
        null,
        Constant.channelVerify,
        (Constant.PROPERTY_VERIFY_IN_CHANNEL_VERIFY |
            Constant.propertyTypeWrite),
        AesUtil.encryptEcbNoPadding(originKey, Cryptor.sAesKey));
  }

  /* **************************** 通道0-连接 END ************************** */

  /* **************************** 通道2-产品信息 START ************************** */

  static LorinMessage genGetDeviceInfoMsg(int property,
      [Uint8ClampedList? para, int? source, int? target]) {
    return genGeneralMsg(Constant.channelInfo, property, para, source, target);
  }

  /*
     * 生成获取产品型号或特征消息
     *
     * @return msg
     */
  static LorinMessage genGetModelMsg([int? source, int? target]) {
    return genGetDeviceInfoMsg(
        Constant.PROPERTY_CHANNEL_INFO_CAR_TYPE, null, source, target);
  }

  /*
     * 生成获取产品整体SN消息
     *
     * @param source 来源设备
     * @param target 目标设备
     * @return msg
     */
  static LorinMessage genGetSnMsg([int? source, int? target]) {
    return genGetDeviceInfoMsg(
        Constant.PROPERTY_CHANNEL_INFO_CAR_SN, null, source, target);
  }

  /*
     * 生成获取电池SN消息
     *
     * @param source 来源设备
     * @param target 目标设备
     * @return msg
     */
  static LorinMessage genGetBatterySnMsg([int? source, int? target]) {
    return genGetDeviceInfoMsg(
        Constant.PROPERTY_CHANNEL_INFO_BATTERY_SN, null, source, target);
  }

  /*
     * 生成获取电机SN消息
     *
     * @param source 来源设备
     * @param target 目标设备
     * @return msg
     */
  static LorinMessage genGetMotorSnMsg([int? source, int? target]) {
    return genGetDeviceInfoMsg(
        Constant.PROPERTY_CHANNEL_INFO_MOTOR_SN, null, source, target);
  }

  /*
     * 生成获取电池容量消息
     *
     * @param source 来源设备
     * @param target 目标设备
     * @return msg
     */
  static LorinMessage genGetBatteryCapacityMsg([int? source, int? target]) {
    return genGetDeviceInfoMsg(
        Constant.PROPERTY_CHANNEL_INFO_BATTERY_CAPACITY, null, source, target);
  }

  /*
     * 生成获取所有设备版本号消息
     *
     * @param source 来源设备
     * @param target 目标设备
     * @return msg
     */
  static LorinMessage genGetFwVersionMsg([int? source, int? target]) {
    return genGetDeviceInfoMsg(
        Constant.PROPERTY_CHANNEL_INFO_VERSION, null, source, target);
  }

  /*
     * 生成获取所有设备版本号消息
     *
     * @param source 来源设备
     * @param target 目标设备
     * @return msg
     */
  static LorinMessage genGetHwVersionMsg([int? source, int? target]) {
    return genGetDeviceInfoMsg(
        Constant.PROPERTY_CHANNEL_INFO_HW_VERSION, null, source, target);
  }

  /*
     * 生成获取额定电压消息
     *
     * @param source 来源设备
     * @param target 目标设备
     * @return msg
     */
  static LorinMessage genGetRatedVoltageMsg([int? source, int? target]) {
    return genGetDeviceInfoMsg(
        Constant.PROPERTY_CHANNEL_INFO_RATED_VOLTAGE, null, source, target);
  }

  /*
     * 生成获取设计最大续航里程消息
     *
     * @param source 来源设备
     * @param target 目标设备
     * @return msg
     */
  static LorinMessage genGetDesignedMaxRemainMileageMsg(
      [int? source, int? target]) {
    return genGetDeviceInfoMsg(
        Constant.PROPERTY_CHANNEL_INFO_DESIGNED_MAX_REMAIN_MILEAGE,
        null,
        source,
        target);
  }

  /*
     * 生成获取设备唯一标识消息
     *
     * @param source 来源设备
     * @param target 目标设备
     * @return msg
     */
  static LorinMessage genGetIdentifierMsg([int? target]) {
    return genGetDeviceInfoMsg(
        Constant.PROPERTY_CHANNEL_INFO_IDENTIFIER, null, null, target);
  }

  /*
     * 生成获取设备激活信息消息
     *
     * @return msg
     */
  static LorinMessage genGetActivateDateMsg() {
    return genGeneralMsg(Constant.channelInfo,
        Constant.PROPERTY_CHANNEL_INFO_ACTIVATE_DATE, null);
  }

  /// 激活
  static LorinMessage genActivateMsg(int target, DateTime dateTime) {
    return genGeneralMany2ManyMsg(
        null,
        target,
        Constant.channelInfo,
        Constant.PROPERTY_CHANNEL_INFO_ACTIVATE_DATE |
            Constant.propertyTypeWrite,
        Datetime.fromDateTime(dateTime).toBytes());
  }

  /*
     * 生成获取云盒device id
     *
     * @param source 来源设备
     * @param target 目标设备
     * @return msg
     */
  static LorinMessage genTBoxDeviceId([int? target]) {
    return genGetDeviceInfoMsg(
        Constant.PROPERTY_CHANNEL_INFO_TBOX_DEVICEID, null, null, target);
  }

  /*
      * 绑定胎压传感器
      *
      * @param source 来源设备
      * @param target 目标设备
      * @return msg
      */
  static LorinMessage genBindTirePressureSensor([Uint8ClampedList? param]) {
    return genGeneralMsg(Constant.channelInfo, Constant.BINDING_TIRE_PRESSURE_SENSOR, param);
  }

/* ***************************** 通道2-产品信息 END *************************** */

/* ***************************** 通道3-通用控制 START *************************** */

  static LorinMessage genGeneralCtrlMsg(int property,
      [Uint8ClampedList? para, int? source, int? target]) {
    return genGeneralMsg(Constant.channelCtrl, property, para, source, target);
  }

  static LorinMessage genPowerCtrlMsg(
    int type, [
    int? source,
    int? target,
  ]) {
    return genGeneralCtrlMsg(
        (Constant.PROPERTY_SHUTDOWN | Constant.propertyTypeWrite),
        Uint8ClampedList.fromList([type]),
        source,
        target);
  }

  static LorinMessage genShutdownMsg([
    int? source,
    int? target,
  ]) {
    return genPowerCtrlMsg(Constant.SHUTDOWN_TYPE_SHUTDOWN, source, target);
  }

  static LorinMessage genRebootMsg([
    int? source,
    int? target,
  ]) {
    return genPowerCtrlMsg(Constant.SHUTDOWN_TYPE_REBOOT, source, target);
  }

  static LorinMessage genPowerCtrlConfirmMsg([int? source, int? target]) {
    return genGeneralCtrlMsg(
        (Constant.PROPERTY_SHUTDOWN_CONFIRM | Constant.propertyTypeWrite),
        null,
        source,
        target);
  }

  /*
     * 出厂重置
     *
     * @param level 重置级别
     * @return
     * @see Constant#FACTORY_RESET_LEVEL_0
     */
  static LorinMessage genFactoryResetMsg(int level) {
    return genGeneralMany2ManyMsg(
        null,
        null,
        Constant.channelCtrl,
        (Constant.PROPERTY_FACTORY_RESET | Constant.propertyTypeWrite),
        Uint8ClampedList.fromList([level]));
  }

  static LorinMessage genStartUpgradingFirmwareMsg(
    int target, [
    Uint8ClampedList? para,
  ]) {
    return genGeneralMany2ManyMsg(
        null,
        target,
        Constant.channelCtrl,
        (Constant.PROPERTY_FIRMWARE_STATUS |
            Constant.propertyTypeWrite) /* 写操作 */,
        para);
  }

  static LorinMessage genGetFirmwareUpgradingStatusMsg() {
    return genGeneralMany2ManyMsg(
        null, null, Constant.channelCtrl, Constant.propertyTypeWrite);
  }

  static LorinMessage genForceUpgradeMsg(int target, int level,
      Uint8ClampedList minVersion, Uint8ClampedList maxVersion) {
    Uint8ClampedList para =
        Uint8ClampedList(1 + minVersion.length + maxVersion.length);
    para[0] = level;
    ByteUtil.copy(minVersion, 0, para, 1, minVersion.length);
    ByteUtil.copy(
        maxVersion, 0, para, 1 + minVersion.length, maxVersion.length);
    return genGeneralMany2ManyMsg(null, target, Constant.channelCtrl,
        (Constant.propertyTypeWrite | Constant.PROPERTY_FORCE_UPGRADE), para);
  }

  static LorinMessage genGetForceUpgradeStateMsg(int target) {
    return genGeneralMany2ManyMsg(
        null, target, Constant.channelCtrl, Constant.PROPERTY_FORCE_UPGRADE);
  }

  static LorinMessage genGetLostModeStateMsg(int target) {
    return genGeneralMany2ManyMsg(
        null, target, Constant.channelCtrl, Constant.PROPERTY_LOST_MODE);
  }

  static LorinMessage genEnableLostModeMsg(int target, int level) {
    return genGeneralMany2ManyMsg(
        null,
        target,
        Constant.channelCtrl,
        (Constant.propertyTypeWrite | Constant.PROPERTY_LOST_MODE),
        Uint8ClampedList.fromList([level]));
  }

  static LorinMessage genDisableLostModeMsg(int target) {
    return genGeneralMany2ManyMsg(
        null,
        target,
        Constant.channelCtrl,
        (Constant.propertyTypeWrite | Constant.PROPERTY_LOST_MODE),
        Uint8ClampedList.fromList([0]));
  }

  /* ***************************** 通道3-通用控制 END *************************** */

  /* ***************************** 通道4-文件操作 START *************************** */

  static LorinMessage genOpenFileMsg(String path, int openType, [int? target]) {
    Uint8ClampedList param = ByteUtil.buildBytes(
        ByteUtil.num2BytesLe(openType, 1),
        ByteUtil.str2Bytes(path, false),
        Uint8ClampedList.fromList([0]));
    return genGeneralMsg(
        Constant.channelFile,
        (Constant.propertyOpenFile | Constant.propertyTypeWrite),
        param,
        null,
        target);
  }

  static LorinMessage genGetFileMsg(int fileHandle, int offset, int length,
      [int? tab, int? target]) {
    return genGeneralMsg(
        Constant.channelFile,
        Constant.propertyReadWriteFile,
        ByteUtil.buildBytes(ByteUtil.num2BytesLe(fileHandle, 1),
            ByteUtil.num2BytesLe(offset, 4), ByteUtil.num2BytesLe(length, 1)),
        null,
        target,
        tab);
  }

  /*
     * @param tab        包标签号
     * @param fileHandle
     * @param offset
     * @param content
     * @return
     */
  static LorinMessage genWriteFileMsg(
      int fileHandle, int offset, Uint8ClampedList content,
      [int? tab, int? target]) {
    return genGeneralMsg(
        Constant.channelFile,
        (Constant.propertyReadWriteFile | Constant.propertyTypeWrite),
        ByteUtil.buildBytes(ByteUtil.num2BytesLe(fileHandle, 1),
            ByteUtil.num2BytesLe(offset, 4), content),
        null,
        target,
        tab);
  }

  static LorinMessage genGetFileCheckMsg(int fileHandle, int offset,
      [int? target]) {
    return genGeneralMsg(
        Constant.channelFile,
        Constant.propertyCheckFile,
        ByteUtil.buildBytes(ByteUtil.num2BytesLe(fileHandle, 1),
            ByteUtil.num2BytesLe(offset, 4)),
        null,
        target);
  }

  static LorinMessage genCheckFileMsg(
      int fileHandle, int length, int offset, Uint8ClampedList crc32,
      [int? target]) {
    return genGeneralMsg(
        Constant.channelFile,
        (Constant.propertyCheckFile | Constant.propertyTypeWrite),
        ByteUtil.buildBytes(
            ByteUtil.num2BytesLe(fileHandle, 1),
            ByteUtil.num2BytesLe(length, 4),
            ByteUtil.num2BytesLe(offset, 4),
            crc32),
        null,
        target);
  }

  static LorinMessage genCloseFileMsg(int fileHandle, [int? target]) {
    return genGeneralMsg(
        Constant.channelFile,
        (Constant.propertyCloseFile | Constant.propertyTypeWrite),
        ByteUtil.buildBytes(ByteUtil.num2BytesLe(fileHandle, 1)),
        null,
        target);
  }

  static LorinMessage genGetFileInfoMsg(String path, [int? target]) {
    return genGeneralMsg(Constant.channelFile, Constant.propertyGetFileInfo,
        ByteUtil.str2Bytes(path), null, target);
  }

  static LorinMessage genDeleteFileMsg(String path, [int? target]) {
    return genGeneralMsg(
        Constant.channelFile,
        (Constant.propertyDeleteFile | Constant.propertyTypeWrite),
        ByteUtil.str2Bytes(path, true),
        null,
        target);
  }

  static LorinMessage genRenameFileMsg(String file, String newFile,
      [int? target]) {
    return genGeneralMsg(
        Constant.channelFile,
        (Constant.propertyRenameFile | Constant.propertyTypeWrite),
        ByteUtil.str2Bytes(file + ">" + newFile),
        null,
        target);
  }

  static LorinMessage genGetFileListMsg(int index, String ctrl, [int? target]) {
    return genGeneralMsg(
        Constant.channelFile,
        Constant.propertyGetFileList,
        index == 0
            ? ByteUtil.buildBytes(
                ByteUtil.num2BytesLe(index, 2), ByteUtil.str2Bytes(ctrl))
            : ByteUtil.buildBytes(ByteUtil.num2BytesLe(index, 2)));
  }

  /* ***************************** 通道4-文件操作 END *************************** */

  /* ***************************** 通道5-存储设备操作 START *************************** */

  static LorinMessage genGeneralStorageMsg(
    int property,
    Uint8ClampedList para, [
    int? source,
    int? target,
  ]) {
    return genGeneralMsg(
        Constant.channelStorage, property, para, source, target);
  }

  static LorinMessage genStorageCapacityMsg(int diskIndex,
      [int? source, int? target]) {
    return genGeneralStorageMsg(
      Constant.PROPERTY_STORAGE_CAPACITY,
      Uint8ClampedList.fromList([diskIndex]),
      source,
      target,
    );
  }

  static LorinMessage genStorageEraseMsg(int diskIndex,
      [int? source, int? target]) {
    return genGeneralStorageMsg(
        (Constant.PROPERTY_STORAGE_INFO | Constant.propertyTypeWrite),
        Uint8ClampedList.fromList([diskIndex, Constant.STORAGE_DATA_ERASE]),
        source,
        target);
  }

/* ***************************** 通道5-存储设备操作 END *************************** */
}
